package com.zoiz.plus.template;

import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeInstance;

import com.zoiz.plus.Config;
import com.zoiz.plus.extend.CommonUtils;


/**
 * Template factory using Velocity.
 * 
 * @author Michael Liao (askxuefeng@gmail.com)
 */
public class VelocityTemplateFactory extends TemplateFactory {

	private final Log log = LogFactory.getLog(getClass());

	// velocity runtime instance as singleton:
	private RuntimeInstance rtInstance;

	private String inputEncoding = "UTF-8";
	private String outputEncoding = "UTF-8";

	/**
	 * Get input encoding of template. Default to UTF-8, can be specified by
	 * 'input.encoding' in velocity.properties.
	 */
	public String getInputEncoding() {
		return inputEncoding;
	}

	/**
	 * Get output encoding of template. Default to UTF-8, can be specified by
	 * 'output.encoding' in velocity.properties.
	 */
	public String getOutputEncoding() {
		return outputEncoding;
	}

	public Template loadTemplate(String path) throws Exception {
		if (log.isDebugEnabled())
			log.debug("Load Velocity template '" + path + "'.");
		return new VelocityTemplate(
				rtInstance.getTemplate(path, inputEncoding), null,
				outputEncoding);
	}

	public void init(Config config) {
		String webAppPath = CommonUtils.getWebAppPath(config.getServletContext());
		log.info("init VelocityTemplateFactory...");
		rtInstance = new RuntimeInstance();
		// read property file:
		Properties props = CommonUtils.readProperties(webAppPath
				+ "/WEB-INF/velocity.properties");
		checkProperty(props);
		Set<?> keys = props.keySet();
		for (Object key : keys) {
			if (key instanceof String) {
				Object value = props.get(key);
				rtInstance.addProperty((String) key, value);
			}
		}
		try {
			Object loaderpath = rtInstance.getProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH);
			if (loaderpath == null) {
				rtInstance.setProperty(
						RuntimeConstants.FILE_RESOURCE_LOADER_PATH, webAppPath);
				log.info("Using web application context path as velocity template root path: "
						+ webAppPath);
			} else if(loaderpath.toString().startsWith(".")){
				rtInstance.setProperty(
						RuntimeConstants.FILE_RESOURCE_LOADER_PATH, webAppPath+loaderpath.toString().substring(1));
			}else{
				log.info("Velocity property \""
						+ RuntimeConstants.FILE_RESOURCE_LOADER_PATH
						+ "\" has been specified in \"/WEB-INF/velocity.properties\".");
				log.info("To using web application context path, remove property \""
						+ RuntimeConstants.FILE_RESOURCE_LOADER_PATH
						+ "\" from configuration file.");
			}
			rtInstance.init();
			afterVelocityEngineInit(rtInstance);
		} catch (Exception e) {
			log.error("VelocityTemplateFactory init failed.", e);
			throw new ExceptionInInitializerError(e);
		}
	}

	void checkProperty(Properties props) {
		this.inputEncoding = setDefaultPropertyIfNotExist(props,
				"input.encoding", "UTF-8");
		this.outputEncoding = setDefaultPropertyIfNotExist(props,
				"output.encoding", "UTF-8");
	}

	String setDefaultPropertyIfNotExist(Properties props, String key,
			String defaultValue) {
		String value = props.getProperty(key);
		if (value == null || value.length() == 0) {
			props.setProperty(key, defaultValue);
		}
		return props.getProperty(key);
	}

	protected void afterVelocityEngineInit(RuntimeInstance instance) {
		// let subclass do some work
	}
}
